﻿using System;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Ecobee.Net
{
	/// <summary>
	/// 
	/// </summary>
	public class Access : SecurityObject
	{
		/// <summary>
		/// This event is fired whenever the Access object is updated. This allows
		/// the owner of this object to updated the stored version to ensure
		/// the most recent Access tokens are saved.
		/// </summary>
		public event EventHandler AccessTokenChanged = null;

		private Api _api = null;
		private Token _accessToken = new Token(Token.Kind.Authorization);
		private string _tokenType = string.Empty;
		private Token _refreshToken = new Token(Token.Kind.Refresh);
		private AuthorizationScope _responseScope = AuthorizationScope.None;

		/// <summary>
		/// 
		/// </summary>
		public Access(Api api)
		{
			this.Api = api;
		}

		/// <summary>
		/// Gets a reference to the active APi instance
		/// </summary>
		protected Api Api
		{
			get
			{
				return _api;
			}
			set
			{
				_api = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[JsonProperty(PropertyName = "access_token")]
		public Token AccessToken
		{
			get
			{
				return _accessToken;
			}
			internal set
			{
				_accessToken = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[JsonProperty(PropertyName = "token_type")]
		public string TokenType
		{
			get
			{
				return _tokenType;
			}
			set
			{
				_tokenType = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[JsonProperty(PropertyName = "refresh_token")]
		public Token RefreshToken
		{
			get
			{
				return _refreshToken;
			}
			internal set
			{
				_refreshToken = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[JsonProperty(PropertyName = "scope")]
		public AuthorizationScope ResponseScope
		{
			get
			{
				return _responseScope;
			}
			set
			{
				_responseScope = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		public bool IsValid
		{
			get
			{
				bool returnValue = false;

				returnValue = this.AccessToken != null && !string.IsNullOrEmpty(this.AccessToken.Identifier);

				return returnValue;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public async Task<bool> Refresh()
		{
			bool returnValue = false;

			if (DateTime.Now >= this.ExpiresAt)
			{
				ApiResult response = await this.Api.Http.Post(this.Api.KnownUri.RefreshToken(this.RefreshToken), null, false);

				if (response.Successful)
				{
					// ***
					// *** Convert this from the json object
					// ***
					this.LoadFrom(response.DataObject);

					// ***
					// *** Fire the changed event for the access token
					// ***
					this.FireAccessTokenChangedEvent();

					// ***
					// *** Return true
					// ***
					returnValue = true;
				}
				else
				{
					response.ThrowException();
				}
			}
			else
			{
				// ***
				// *** Return true
				// ***
				returnValue = true;
			}

			return returnValue;
		}

		/// <summary>
		/// Reset this instance to default values.
		/// </summary>
		public void Reset()
		{
			this.AccessToken = new Token(Token.Kind.Authorization);
			this.RefreshToken = new Token(Token.Kind.Refresh);
			this.TokenType = string.Empty;
			this.ResponseScope = AuthorizationScope.None;
			this.TimeStamp = DateTime.MinValue;

			// ***
			// *** Fire the changed event for the access token
			// ***
			this.FireAccessTokenChangedEvent();
		}

		/// <summary>
		/// 
		/// </summary>
		public void FireAccessTokenChangedEvent()
		{
			this.OnAccessTokenChanged(new EventArgs());
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>		
		public async Task<bool> RequestAccess(Authorization authorization)
		{
			bool returnValue = false;

			ApiResult response = await this.Api.Http.Post(this.Api.KnownUri.RequestAccess(authorization.AuthorizationToken), null);

			if (response.Successful)
			{
				// ***
				// *** Convert this from the json object
				// ***
				this.LoadFrom(response.DataObject);

				// ***
				// *** Fire the changed event for the access token
				// ***
				this.FireAccessTokenChangedEvent();

				// ***
				// *** Return true
				// ***
				returnValue = true;
			}
			else
			{
				// ***
				// *** Reset this object to default values
				// ***
				this.Reset();

				// ***
				// *** Return true
				// ***
				returnValue = false;
			}

			return returnValue;
		}

		protected override void OnLoadFrom(object dataObject)
		{
			this.TimeStamp = DateTime.Now;
			base.OnLoadFrom(dataObject);
		}

		protected virtual void OnAccessTokenChanged(EventArgs e)
		{
			if (this.AccessTokenChanged != null)
			{
				this.AccessTokenChanged(this, e);
			}
		}
	}
}
